Quartz使用Trigger,Job和JobDetail来实现各种调度任务。Quartz的基础概念可以查看http://quartz-scheduler.org。为了方便,Spring提供了在Spring基础应用下简单使用Quartz的数个类。
Quartz JobDetail对象包含了执行一个工作任务的所有必要信息。Spring提供JobDetailFactoryBean以XML格式配置Bean样式的属性。让我们来看一个例子:
<bean name="exampleJob" class="org.springframework.sheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="example.ExampleJob" />
<property name="jobDataAsMap">
<map>
<entry key="timeout" value="5" />
</map>
</property>
</bean>
工作任务细节配置包含了执行的所有需要的信息(ExampleJob)。timeout是在工作任务数据以键值形式被指定。工作任务数据键值可以通过JobExecutionContext工作执行上下文获取(在执行期间传递),但是JobDetail也是通过工作实例被数据映射的属性来得到它的属性值。所以在这个例子中,如果ExampleJob包含了一个名称为timeout的bean属性,JobDetail将会自动获取到:
package example;
public class ExampleJob extends QuarztJobBean {
private int timeout;
/**
* Setter called after the ExampleJob is instantiated
* with the value from the JobDetailFactoryBean(5)
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
}
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
// do the actual work
}
}
通过工作数据键值配置的所有附件属性也都是可用的。
使用
name和group属性,可以分别改变工作的名称和组。工作的名称默认是匹配JobDetailFactoryBean的名称(在上面的例子中,就是exampleJob)
经常需要调用特定对象的方法。使用MethodInvokingJobDetailFactoryBean可以实现这一点:
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="exampleBusinessObject" />
<property name="targetMethod" value="doIt" />
</bean>
上面的例子将会调用exampleBusinessObject对象的doIt方法:
public class ExampleBusinessObject {
// properties and collaborators
public void doIt() {
// do the actual work
}
}
<bean id="exampleBusinessObject" class="examples.ExampleBusinessObject" />
使用MethodInvokingJobDetailFactoryBean,不需要去创建一个仅仅实现调用方法的主工作任务,只需创建真正业务逻辑对象和关注对象实现的细节。
Quartz工作任务默认是无状态的,导致的结果工作任务之间会相互干扰。如果给同一个JobDetail指定两个触发器,可能会出现在第一个任务完成之前,第二个任务就要开始了。如果JobDetail类实现了Stateful接口,这种情况就不会发生。在第一个任务完成之前第二个任务将不会开始。为了使任务通过MethodInvokingJobDetailFactoryBean不并发,设置concurrent标志为false。
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="exampleBusinessObject" />
<property name="targetMethod" value="doIt" />
<property name="concurrent" value="false" />
</bean>
默认的工作任务是在并发形式下执行的
我们已经创建了工作任务和任务的实现。也有方便的bean来调用指定的对象方法。我们仍然需要这些工作任务自己进行调度。使用触发器和SchedulerFactoryBean来完成。Quartz实现了几个触发器,Spring提供两个方便的Quartz FactoryBean实现:CronTriggerFactoryBean和SimpleTriggerFactoryBean。
触发器是需要被安排调用的。Spring提供SchedulerFactoryBean使触发器做可以设置的属性暴露出来。SchedulerFactoryBean使用触发器来安排调用工作任务。
下面是两个例子:
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<!-- see the example of method invoking job above -->
<property name="jobDetail ref="jobDetail" />
<!-- 10 seconds -->
<property name="startDelay" value="10000" />
<!-- repeat every 50 seconds -->
<property name="repeatInterval" value="50000" />
</bean>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="exampleJob" />
<!-- run every morning at 6 AM -->
<property name="cronExpression" value="0 0 6 * * ?" />
</bean>
现在我们已经设置了两个触发器,一个每隔50秒延迟10秒启动一个次和一个每天在上6点执行。最后我们需要设置SchedulerFactoryBean:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger" />
<ref bean="simpleTrigger" />
</list>
</property>
</bean>
SchedulerFactoryBean更多的可设置属性,例如工作任务实现使用的calendars,Quartz自定义的属性等等。查看SchedulerFactoryBean的javadocs了解更多信息。